<?php

class Menu
{
	/**
	 * menu name
	 * @var string
	 */
	protected $_name = null;

	/**
	 * config of this menu
	 * @var array
	 */
	protected $_config = null;

	/**
	 * @param string $name
	 * @param array $config
	 * @return void
	 */
	protected function __construct($name, $config = null)
	{
		$this -> _name = $name;
		$this -> _config = (array)$config;
	}

	/**
	 * @param string $name
	 * @param array $config
	 */
	static public function factory($name, $config = null)
	{
		return new self($name, $config);
	}

	/**
	 * @return html
	 */
	protected function _renderItem($item, $sub)
	{
		$css_class = isset($item['css_class']) ? $item['css_class'] : null;
		$css_id = isset($item['css_id']) ? $item['css_id'] : null;

		if (isset($item['type']))
		{
			if ($item['type'] == 'html')
			{
				return sprintf('<li class="%s" id="%s">%s%s</li>', $css_class, $css_id, $item['html'], $sub);
			}
		}

		{
			$pattern = '<li class="%s" id="%s"><a href="%s"><span>%s</span></a>%s</li>';
			$url = Agilet::getUrl($item['url']);
			return sprintf($pattern, $css_class, $css_id, $url, __text($item['label']), $sub);
		}

	}

	/**
	 * @return string
	 */
	protected function _render($data, $level)
	{
		$items = array();

		if ($level == 0)
		{
			$items = isset($data['items']) ? $data['items'] : array();
		}
		else
		{
			$items = $data;
		}

		if (empty($items))
		{
			return '';
		}

		$xhtml = array();

		$css_class = isset($data['css_class']) ? $data['css_class'] : null;

		$css_id = isset($data['css_id']) ? $data['css_id'] : null;

		$clearfix = isset($data['clearfix']) ? $data['clearfix'] : false;

		foreach ($items as $item)
		{
			try
			{
				if (isset($item['type']))
				{
					if ($item['type'] == 'plugin')
					{
						list($plugin, $method) = explode(':', $item['plugin']);
						$obj = Agilet::getPlugin($plugin);
						$item = $obj -> {$method}($item);
					}
				}

				if (null == $item)
				{
					continue;
				}

				$sub = '';

				if (isset($item['items']) && $item['items'])
				{
					$sub = $this -> _render($item['items'], $level + 1);
				}

				$xhtml[] = $this -> _renderItem($item, $sub);

			}
			catch(Exception $e)
			{
				Logger::write(Logger::ERROR, $e -> getMessage());
			}
		}

		$xhtml = sprintf('<ul class="%s" id="%s">%s</ul>', $css_class, $css_id, implode(PHP_EOL, $xhtml));

		if ($level == 0 AND $clearfix)
		{
			$xhtml .= '<div class="clearfix"></div>';
		}
		return $xhtml;
	}

	public function loadData()
	{

		// reprocess this type of data.
		$table = Model::getTable('core/menu');

		$menu = $table -> fetchRow($table -> select() -> where('name=?', $this -> _name));

		if (null == $menu)
		{
			return array();
		}

		$table = Model::getTable('core/menuitem');

		$select = $table -> select() -> where('menu_id=?', $menu -> getId()) -> where('is_active=?', 1) -> order('sort_order ASC');

		$temp_items = $table -> fetchAll($select) -> toArray();

		// final list of items.
		$items = array();

		// map parent_item_id => parent_id
		foreach ($temp_items as $item)
		{
			$items[$item['item_id']] = $item;
		}

		unset($temp_items);

		for ($i = 0; $i < 10; ++$i)
		{

			// define some thing else.
			$map_p2c = array();
			$found = false;

			// map parent_item_id => parent_id
			foreach ($items as $item)
			{
				$map_p2c[$item['parent_id']] = 1;
			}

			foreach ($items as $key => $item)
			{
				$id = $item['item_id'];
				$pid = $item['parent_id'];

				// process p1.
				if (0 == $pid)
				{
					continue;
				}

				if (!isset($map_p2c[$id]) && $map_p2c[$pid] == 1)
				{
					$found = true;
					if (isset($items[$pid]) && is_array($items[$pid]))
					{
						$items[$pid]['items'][] = $item;
					}
					unset($items[$key]);
				}
				else
				{
					// temporary block parent node.
					$map_p2c[$pid] = 2;
				}
			}
			if (!$found)
			{
				break;
			}
		}

		$data = array(
			'css_id' => $menu -> css_id,
			'css_class' => $menu -> css_class,
			'clearfix' => $menu -> clearfix,
			'items' => $items,
		);

		return $data;

	}

	/**
	 * @return string
	 */
	public function render()
	{
		$data = $this -> loadData();
		if ($this -> _config)
		{
			if (isset($this -> _config['css_id']))
			{
				$data['css_id'] = $this -> _config['css_id'];
			}
			if (isset($this -> _config['css_class']))
			{
				$data['css_class'] = $this -> _config['css_class'];
			}
			if (isset($this -> _config['clear_fix']))
			{
				$data['clear_fix'] = $this -> _config['clear_fix'];
			}

		}
		return $this -> _render($data, 0);
	}

	/**
	 * @return string
	 */
	public function renderConfigure()
	{
		return $this -> _renderConfigure($this -> loadData(), 0);
	}

	protected function _renderConfigure($data, $level)
	{
		$items = array();

		if ($level == 0)
		{
			$items = isset($data['items']) ? $data['items'] : array();
		}
		else
		{
			$items = $data;
		}

		if (empty($items))
		{
			return '';
		}

		$xhtml = array();

		foreach ($items as $item)
		{
			try
			{
				if (isset($item['items']) && $item['items'])
				{
					$sub = $this -> _renderConfigure($item['items'], $level + 1);
				}

				$xhtml[] = $this -> _renderConfigureItem($item, $sub);
			}
			catch(Exception $e)
			{
				Logger::write(Logger::ERROR, $e -> getMessage());
			}
		}

		$xhtml = sprintf('<ul class="editAdminMenu">%s</ul>', implode(PHP_EOL, $xhtml));

		return $xhtml;
	}

	/**
	 * @return html
	 */
	protected function _renderConfigureItem($item, $sub)
	{
		return sprintf('<li>%s [ <a href="%s">edit</a> - <a href="%s">remove</a> ]%s</li>', $item['label'], Agilet::getUrl('admin/system/appearance/menu/item/edit', array('item_id' => $item['item_id'])), Agilet::getUrl('admin/system/appearance/menu/item/delete', array('item_id' => $item['item_id'])), $sub);
	}

}
